package com.wlin.leaf;

import com.wlin.leaf.utils.IpPortUtils;
import com.wlin.leaf.utils.ZkClientTools;
import org.apache.zookeeper.CreateMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.management.MalformedObjectNameException;
import java.io.File;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.ArrayList;

/**
 * Copyright (c) 2010-3020 Zhongshan Pole 3D Electronic Tech. Co., Ltd. All Rights Reserved.
 * <p>
 * This software is the confidential and proprietary information of
 * Zhongshan Pole 3D Electronic Tech. You shall not disclose such Confidential Information
 * and shall use it only in accordance with the terms of the agreements
 * you entered into with Zhongshan Pole 3D Electronic Tech.
 * <p>
 * 项目名称：diyhome-parent
 * 类名称：ZkWorkIdGetterStrategy
 * 类描述： ${DESCRIPTION}
 *
 * @author wlin
 * @version 1.0
 * @since 2018/9/21
 */
@Component
public class ZkWorkIDStrategy implements WorkerIdObtainStrategy {

    private static Logger logger = LoggerFactory.getLogger(ZkWorkIDStrategy.class);


    private ZkClientTools zkClientTools;

    private ZkWorkIDProperties properties;

    public ZkWorkIDStrategy(ZkWorkIDProperties properties) {
        this.properties = properties;
    }

    @Override
    public Integer getCurrentWorkId() throws Exception {

        String currentClientPrefix = getCurrentClientPrefix();
        //1.检查本地文件是否存在,存在则直接返回
        String holderRootPath = getHolderRootPath();
        String holderFileName = IdHolderFileUtil.getLocalHolderFileName(holderRootPath);
        if(holderFileName != null){
            //如果前缀对应，则环境一致，直接返回ID
            if(holderFileName.startsWith(currentClientPrefix)){
                return getWorkId(holderFileName,currentClientPrefix);
            }
            //如果前缀不一致，说明环境已经发生变化，清除旧holder文件
            new File(holderRootPath,holderFileName).delete();
        }

        //2.本地holder文件不存在，访问zookeeper
        initZkClientTools();// 初始化zookeeper连接工具
        String rootNodeName = getRootNodeName();
        ZkClientTools.ChildrenNodesStat stat = zkClientTools.getChildren(rootNodeName);
        // 2.1 检查是否已注册，如果已注册，使用之前注册的workId
        String node ;
        if (stat != null && stat.hasNodeStartWith(currentClientPrefix)) {
            node = stat.getNodeStartWith(getCurrentClientPrefix());
        }else {
            //  如果未注册，注册一个新的workId 节点
            node = zkClientTools.createNode(CreateMode.PERSISTENT_SEQUENTIAL,rootNodeName + "/"+ getCurrentClientPrefix());
            node = node.startsWith(rootNodeName) ? node.replace(rootNodeName+ "/","") : node;
        }
        // 2.2 创建workId 本地holder文件
        IdHolderFileUtil.touchHolderFile(holderRootPath,node);
        Integer workId = getWorkId(node,currentClientPrefix);

        destroyZkClientTools(); //当前为启动时一次获取，后续无需再连接，故获取后即关闭连接。如需多次使用，此处可以不关闭连接。
        return workId;
    }


    private String getRootNodeName() {
        String rootNodeName = properties.getZookeeperRootNode();
        logger.info("[ zookeeperRootNode={} ]",rootNodeName);
        return rootNodeName;
    }

    private String getHolderRootPath() {
        String holderRootPath = properties.getHolderRootPath();
        logger.info("[ holderRootPath={} ]",holderRootPath);
        return holderRootPath;
    }

    private void initZkClientTools() {
        if(zkClientTools == null) {
            synchronized (this) {
                if(zkClientTools == null) {
                    String zkHost = properties.getZookeeperHost();
                    if (zkHost == null || "".equals(zkHost)) {
                        throw new IllegalStateException("zkHost can not be empty");
                    }
                    zkClientTools = ZkClientTools.Builder.build(zkHost);
                }
            }
        }
    }

    private void destroyZkClientTools() {
        zkClientTools.preDestroy();
        zkClientTools = null;
    }

    private Integer getWorkId(String node, String prefix) {
        String idStr = node.substring(prefix.length());
        return Integer.parseInt(idStr);
    }

    private String getCurrentClientPrefix() throws UnknownHostException, MalformedObjectNameException {
        return IpPortUtils.getHostAddress()+ "_" +IpPortUtils.getNonSecurePort() + "-";
    }

    public static class IdHolderFileUtil{
        public static String getLocalHolderFileName(String holderFolder) {
            File rootFolder = getHolderFolderFile(holderFolder);
            if(rootFolder.exists()) {
                ArrayList<String> files = new ArrayList<String>();
                File[] list = rootFolder.listFiles();
                for (File f : list) {
                    files.add(f.getName());
                }
                if(files.size() > 1)
                if(!files.isEmpty()){
                    return files.get(0);
                }
            }
            return null;
        }

        public static void touchHolderFile(String holderFolder, String node) throws IOException {
            File rootFolder = getHolderFolderFile(holderFolder);
            if(!rootFolder.exists()) {
                rootFolder.mkdirs();
            }
            File file = new File(rootFolder,node);
            file.createNewFile();
        }

        private static File getHolderFolderFile(String holderFolder) {
            return new File(Thread.currentThread().getContextClassLoader().getResource("").getPath() + File.separator+ holderFolder);
        }
    }


}